package com.runa.protocol.enums;

public class S7Enum {

    /**
     * S7协议数据单元类型
     */
    public enum PDUType {
        JOB((byte) 1),
        ACK((byte) 2),
        ACK_DATA((byte) 3),
        EXTEND((byte) 7);

        private byte code;

        PDUType(byte code) {
            this.code = code;
        }

        public byte getCode() {
            return code;
        }

        public static PDUType valueOf(byte code) {
            for (PDUType type : PDUType.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 功能码
     */
    public enum FunCode {
        COMM_SET((byte) 0xf0),
        READ((byte) 4),
        WRITE((byte) 5);

        private byte code;

        FunCode(byte code) {
            this.code = code;
        }

        public byte getCode() {
            return code;
        }

        public static FunCode valueOf(byte code) {
            for (FunCode type : FunCode.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * Transport size (variable Type) in Item data
     */
    public enum Variable {
        BIT((byte) 1),
        BYTE((byte) 2),
        CHAR((byte) 3),
        WORD((byte) 4),
        INT((byte) 5),
        DWORD((byte) 6),
        DINT((byte) 7),
        REAL((byte) 8),
        DATE((byte) 9),
        TOD((byte) 10),
        TIME((byte) 11),
        S5TIME((byte) 12),
        DATE_TIME((byte) 13),
        COUNTER((byte) 0x1C),
        TIMER((byte) 0x1D),
        IEC_TIMER((byte) 0x1E),
        IEC_COUNTER((byte) 0x1F),
        HS_COUNTER((byte) 0x20);

        private byte code;

        Variable(byte code) {
            this.code = code;
        }

        public static Variable valueOf(byte code) {
            for (Variable type : Variable.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }

        public byte getCode() {
            return code;
        }
    }

    /**
     * Transport size in data
     */
    public enum TransportSize {
        NULL((byte) 0),
        BIT((byte) 3),
        BYTE((byte) 4),
        WORD((byte) 4),
        DWORD((byte) 4),
        INTEGER((byte) 5),
        REAL((byte) 7),
        OCTET_STRING((byte) 9);

        private byte code;

        TransportSize(byte code) {
            this.code = code;
        }

        public static TransportSize valueOf(byte code) {
            for (TransportSize type : TransportSize.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }

        public byte getCode() {
            return code;
        }
    }

    /**
     * Memory Areas
     */
    public enum Area {
        INPUT((byte) 0x81),
        OUTPUT((byte) 0x82),
        MERKER((byte) 0x83),
        DATA_BLOCK((byte) 0x84),
        DATA_BLOCK_INS((byte) 0x85),
        LOCAL_DATA((byte) 0x86),
        VARIABLE((byte) 0x87);

        private byte code;

        Area(byte code) {
            this.code = code;
        }

        public byte getCode() {
            return code;
        }

        public static Area valueOf(byte code) {
            for (Area type : Area.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }

        public static Area getByTag(String tag) {
            switch (tag) {
                case "I":
                    return INPUT;
                case "Q":
                    return OUTPUT;
                case "M":
                    return MERKER;
                case "DB":
                    return DATA_BLOCK;
                case "DI":
                    return DATA_BLOCK_INS;
                case "L":
                    return LOCAL_DATA;
                case "V":
                    return VARIABLE;
            }
            return null;
        }
    }

    /**
     * Return value of item response
     */
    public enum ReturnCode {
        RESERVED((byte) 0, "保留"),
        HARDWARE_FAULT((byte) 1, "硬件错误"),
        NOT_ALLOWED((byte) 3, "不允许访问对象"),
        OUT_RANGE((byte) 5, "地址超范围"),
        NOT_SUPPORT((byte) 6, "不支持的数据类型"),
        INCONSISTENT((byte) 7, "数据类型矛盾"),
        NOT_EXIST((byte) 0x0a, "对象不存在"),
        SUCCESS((byte) 0xff, "成功");

        private byte code;
        private String msg;

        ReturnCode(byte code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public byte getCode() {
            return code;
        }

        public static ReturnCode valueOf(byte code) {
            for (ReturnCode type : ReturnCode.values()) {
                if (type.code == code) {
                    return type;
                }
            }
            return null;
        }

        public String getMsg() {
            return msg;
        }
    }
}
